const canvas = document.querySelector('canvas')
const gl = canvas.getContext('webgl')

const vertex = `
  attribute vec2 position;
  uniform float u_rotation;
  uniform float u_time;
  uniform float u_duration;
  uniform float u_scale;
  uniform float u_skew;
  uniform vec2 u_dir;
  
  varying float vP;
  void main() {
    float p = min(1.0, u_time / u_duration);
    float rad = u_rotation + 3.14 * 10.0 * p;
    float scale = u_scale * p * (2.0 - p);
    vec2 offset = 2.9 * u_dir * p * p;
    mat3 translateMatrix = mat3(
      1.0, 0.0, 0.0,
      0.0, 1.0, 0.0,
      offset.x, offset.y, 1.0
    );
    mat3 rotateMatrix = mat3(
      cos(rad), sin(rad), 0.0,
      -sin(rad), cos(rad), 0.0,
      0.0, 0.0, 1.0
    );
    mat3 scaleMatix = mat3(
      scale, 0.0, 0.0,
      0.0, scale, 0.0,
      0.0, 0.0, 1.0
    );

    mat3 skewMatix = mat3(
      1.0, tan(u_skew), 0.0,
      tan(u_skew), 1.0, 0.0,
      0.0, 0.0, 1.0
    );
    gl_PointSize = 1.0;
    vec3 pos = translateMatrix * rotateMatrix * scaleMatix * skewMatix * vec3(position, 1.0);
    gl_Position = vec4(pos, 1.0);
    vP = p;
  }
`;


const fragment = `
  precision mediump float;
  uniform vec4 u_color;
  varying float vP;
  void main()
  {
    gl_FragColor.xyz = u_color.xyz;
    gl_FragColor.a = (1.0 - vP) * u_color.a;

  }    
`;

const vertexShader = gl.createShader(gl.VERTEX_SHADER)
gl.shaderSource(vertexShader, vertex)
gl.compileShader(vertexShader)

let success = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS);
if (!success) {
  console.log(gl.getShaderInfoLog(vertexShader));
}

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
gl.shaderSource(fragmentShader, fragment)
gl.compileShader(fragmentShader)

success = gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS);
if (!success) {
  console.log(gl.getShaderInfoLog(fragmentShader));
}


const program = gl.createProgram()
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)
gl.linkProgram(program)
gl.useProgram(program)

const position = new Float32Array([
  -1, -1,
  0, 1,
  1, -1
])

const bufferId = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId)
gl.bufferData(gl.ARRAY_BUFFER, position, gl.STATIC_DRAW)

const vPosition = gl.getAttribLocation(program, 'position')
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0)
gl.enableVertexAttribArray(vPosition)

// gl.drawArrays(gl.LINE_LOOP, 0, position.length / 2)
gl.drawArrays(gl.TRIANGLES, 0, position.length / 2)

function randomTriangles() {
  const u_color = [Math.random(), Math.random(), Math.random(), 1.0]
  const u_rotation = Math.random() * Math.PI
  const u_skew = Math.random() * Math.PI / 4
  const u_scale = Math.random() * 0.05 + 0.03
  const u_time = 0
  const u_duration = 3.0

  const rad = Math.random() * Math.PI * 2
  const u_dir = [Math.cos(rad), Math.sin(rad)]
  const startTime = performance.now()

  return {
    u_color,
    u_rotation,
    u_scale,
    u_time,
    u_duration,
    u_dir,
    u_skew,
    startTime
  }
}
/**
 * 
 * @param {*} param1 
 */
function setUniforms({
    u_color,
    u_rotation,
    u_scale,
    u_time,
    u_duration,
    u_dir,
    u_skew,
    startTime
}) {
  let loc = gl.getUniformLocation(program, 'u_color')
  gl.uniform4fv(loc, u_color)

  loc = gl.getUniformLocation(program, 'u_rotation')
  gl.uniform1f(loc, u_rotation)

  loc = gl.getUniformLocation(program, 'u_skew')
  gl.uniform1f(loc, u_skew)
  
  loc = gl.getUniformLocation(program, 'u_scale')
  gl.uniform1f(loc, u_scale)
  loc = gl.getUniformLocation(program, 'u_time')
  gl.uniform1f(loc, u_time)
  loc = gl.getUniformLocation(program, 'u_duration')
  gl.uniform1f(loc, u_duration)
  loc = gl.getUniformLocation(program, 'u_dir')
  gl.uniform2fv(loc, u_dir)
}

let triangles = []

function update() {
  for (let i = 0; i < 5 * Math.random(); i++) {
    triangles.push(randomTriangles())
  }

  gl.clear(gl.COLOR_BUFFER_BIT)

  // set time
  triangles.forEach(triangle => {
    triangle.u_time = (performance.now() - triangle.startTime) / 1000
    setUniforms(triangle)
    gl.drawArrays(gl.TRIANGLES, 0, position.length / 2)
  })

  triangles = triangles.filter(triangle => {
    return triangle.u_time <= triangle.u_duration
  })

  requestAnimationFrame(update)
}

requestAnimationFrame(update)
